package com.kkwrite.regimen.provider.controller.order;

import com.kkwrite.regimen.common.entity.dto.OutDTO;
import com.kkwrite.regimen.common.entity.dto.order.OrderChangePayStatusInDTO;
import com.kkwrite.regimen.common.entity.dto.order.OrderDetailDTO;
import com.kkwrite.regimen.common.entity.dto.order.OrderReviewSubmitInDTO;
import com.kkwrite.regimen.common.entity.dto.order.RefundOutDTO;
import com.kkwrite.regimen.common.entity.dto.order.SubmitOrderInDTO;
import com.kkwrite.regimen.provider.exception.DBNullException;
import com.kkwrite.regimen.provider.exception.OrderCannotCancelException;
import com.kkwrite.regimen.provider.exception.OrderRefundException;
import com.kkwrite.regimen.provider.exception.RegimenProviderException;
import com.kkwrite.regimen.provider.exception.ServiceException;
import com.kkwrite.regimen.provider.service.order.OrderService;
import com.kkwrite.regimen.provider.util.TokenUtil;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import static com.kkwrite.regimen.common.constant.Constant.BOOLEAN_STRING_FALSE;
import static com.kkwrite.regimen.common.constant.Constant.BOOLEAN_STRING_TRUE;

/** 
 * 订单服务
 *
 * @author Soosky Wang
 * @version 1.0.0
 */
@Api(value = "订单模块")
@RestController
@RequestMapping("/order")
public class OrderController {

	private final Logger logger = LoggerFactory.getLogger(this.getClass());

	@Resource(name = "orderService")
	private OrderService orderService;
	@Resource(name = "tokenUtil")
	private TokenUtil tokenUtil;

	private static final List<Integer> ORDER_STATUS_LIST = Arrays.asList(1, 2, 3, 4);

	@GetMapping(value = "/shopcount")
	@ApiOperation(value = "店铺订单统计接口")
	public OutDTO shopCount(@RequestHeader @ApiIgnore String token) {
		String shopIdString = (String) tokenUtil.getValue(token, TokenUtil.TokenKeyEnum.SHOP_ID);
		if (shopIdString == null) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "002", "token invalid");
		}
		try {
			return OutDTO.of(BOOLEAN_STRING_TRUE, "OK", "OK", orderService.countByShopId(Long.valueOf(shopIdString)));
		} catch (Exception e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "服务异常！异常信息：" + e.getMessage());
		}
	}

	@GetMapping(value = "/querypageexceptunpay")
	@ApiOperation(value = "分页查询店铺除待支付的订单列表")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "page", value = "页码", required = true,
					allowableValues = "[0, infinity)", paramType = "query", dataType = "int"),
			@ApiImplicitParam(name = "pageSize", value = "每页条目数", required = true,
					allowableValues = "[1, infinity)", paramType = "query", dataType = "int")
	})
	@HystrixCommand(fallbackMethod = "shopQueryPageableExceptUnpayError")
	public OutDTO shopQueryPageableExceptUnpay(@RequestParam Integer page, @RequestParam Integer pageSize,
											   @ApiIgnore @RequestHeader String token) {
		String shopIdString = (String) tokenUtil.getValue(token, TokenUtil.TokenKeyEnum.SHOP_ID);
		if (shopIdString == null) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "002", "token invalid");
		}
		if (page < 0 || pageSize < 1) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "入参不合法");
		}
		return OutDTO.of(BOOLEAN_STRING_TRUE, "OK", "OK",
				orderService.queryOrderPageableExceptUnpay(shopIdString, page, pageSize));
	}

	public OutDTO shopQueryPageableExceptUnpayError(Integer page, Integer pageSize, String token, Throwable t) {
		logger.error(t.getMessage(), t);
		return OutDTO.of(BOOLEAN_STRING_FALSE, "服务异常！异常信息：" + t.getMessage());
	}

	@GetMapping(value = "/shopquerylist")
	@ApiOperation(value = "分页查询店铺订单列表接口")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "page", value = "页码", required = true,
					allowableValues = "[0, infinity)", paramType = "query", dataType = "int"),
			@ApiImplicitParam(name = "pageSize", value = "每页条目数", required = true,
					allowableValues = "[1, infinity)", paramType = "query", dataType = "int"),
			@ApiImplicitParam(name = "status", value = "订单状态",
					allowableValues = "1,2,3,4", paramType = "query", dataType = "int")
	})
	public OutDTO shopQueryListPageable(@RequestParam Integer page, @RequestParam Integer pageSize,
										@RequestParam(required = false) Integer status, HttpServletRequest request) {
		Object obj = tokenUtil.getValue(request.getHeader("token"), TokenUtil.TokenKeyEnum.SHOP_ID);
		if (obj == null) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "002", "token invalid");
		}
		if (page == null || page < 0 || pageSize == null || pageSize < 1) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "入参不合法");
		}
		if (status != null && !ORDER_STATUS_LIST.contains(status)) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "入参不合法");
		}
		Integer shopId = Integer.valueOf((String) obj);
		try {
			return OutDTO.of(BOOLEAN_STRING_TRUE, "OK", "OK",
					orderService.queryOrderPageable(page, pageSize, null, shopId, status == null ? null : status.shortValue()));
		} catch (DBNullException e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "当前页订单列表为空");
		} catch (RegimenProviderException e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, e.getMessage());
		} catch (Exception e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "分页查询订单列表服务异常！异常信息：" + e.getMessage());
		}
	}

	@PostMapping(value = "/changePayStatus")
	public OutDTO changePayStatus(@RequestBody OrderChangePayStatusInDTO inDTO) {
		try {
			orderService.changePayStatus(inDTO);
		} catch (DBNullException e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "订单不存在");
		} catch (ServiceException e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, e.getMessage());
		} catch (Exception e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "服务异常");
		}
		return OutDTO.of(BOOLEAN_STRING_TRUE, "OK", "OK", null);
	}

	@GetMapping(value = "/count")
	public OutDTO orderCount(@RequestParam String userId, @RequestParam Short orderType) {
		try {
			return OutDTO.of(BOOLEAN_STRING_TRUE, "OK", null, orderService.count(userId, orderType));
		} catch (Exception e) {
			logger.error("订单统计服务异常，异常信息：" + e.getMessage(), e);
			return OutDTO.of(BOOLEAN_STRING_FALSE, "订单统计服务异常，异常信息：" + e.getMessage());
		}
	}

	@PostMapping(value = "/refundNotifyUpdate")
	public OutDTO refundNotifyUpdate(@RequestBody Map<String, String> paramMap) {
		try {
			orderService.updateRefundInfo(paramMap);
		} catch (DBNullException e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "订单不存在");
		} catch (Exception e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "服务异常");
		}
		return OutDTO.of(BOOLEAN_STRING_TRUE, "OK");
	}

	@PostMapping(value = "/updateTradeState")
	public OutDTO updateTradeState(@RequestBody Map<String, String> paramMap) {
		orderService.updateTradeState(paramMap);
		return OutDTO.of(BOOLEAN_STRING_TRUE, "OK");
	}

	@GetMapping(value = "/refund/{orderCode}")
	public OutDTO<RefundOutDTO> orderRefund(@PathVariable String orderCode) {
		try {
			return OutDTO.of(BOOLEAN_STRING_TRUE, null, null, orderService.refund(orderCode));
		} catch (DBNullException e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "订单不存在", null, null);
		} catch (OrderRefundException e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, e.getMessage(), null, null);
		} catch (Exception e) {
			logger.error("订单 {} 发起退款异常！", orderCode);
			logger.error(e.getMessage(), e);
			return OutDTO.of(BOOLEAN_STRING_FALSE, "服务异常！", null, null);
		}
	}

	@GetMapping(value = "/queryPageable")
	public OutDTO queryPageable(Integer page, Integer pageSize, Integer userId, Short status, Short orderType) {
		try {
			return OutDTO.of(BOOLEAN_STRING_TRUE, "OK", "OK",
					orderService.queryOrderPageable(page, pageSize, userId, null, status, orderType));
		} catch (DBNullException e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "当前页订单列表为空");
		} catch (RegimenProviderException e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, e.getMessage());
		} catch (Exception e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "分页查询订单列表服务异常！异常信息：" + e.getMessage());
		}
	}

	@GetMapping(value = "/service/{orderCode}")
	public OutDTO changeServiceStatus(@PathVariable String orderCode, Integer type) {
		try {
			orderService.changeServiceStatus(orderCode, type);
			return OutDTO.of(BOOLEAN_STRING_TRUE, "变更完成");
		} catch (DBNullException e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "订单不存在");
		} catch (ServiceException e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, e.getMessage());
		} catch (Exception e) {
			logger.error("订单 {} 状态变更异常，变更类型：{}", orderCode, type);
			logger.error(e.getMessage(), e);
			return OutDTO.of(BOOLEAN_STRING_FALSE, "服务异常！");
		}
	}

	@GetMapping(value = "/cancel/{orderCode}")
	public OutDTO cancelOrder(@PathVariable String orderCode) {
		try {
			orderService.cancel(orderCode);
			return OutDTO.of(BOOLEAN_STRING_TRUE, "订单取消成功");
		} catch(OrderCannotCancelException e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, e.getMessage());
		} catch (DBNullException e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "该订单不存在");
		} catch (Exception e) {
			logger.error("取消订单{}发生异常！", orderCode);
			logger.error(e.getMessage(), e);
			return OutDTO.of(BOOLEAN_STRING_FALSE, "服务异常！");
		}
	}

	@GetMapping(value = "/continuePay/{orderCode}")
	public OutDTO continuePay(@PathVariable String orderCode) {
		try {
			return OutDTO.of(BOOLEAN_STRING_TRUE, null, null, orderService.continuePay(orderCode));
		} catch (DBNullException e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "该订单不存在");
		} catch (ServiceException e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, e.getMessage());
		} catch (Exception e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "服务异常！");
		}
	}

	@PostMapping(value = "/submit/{userId}")
	public OutDTO submitOrder(@PathVariable Integer userId, @RequestBody SubmitOrderInDTO inDTO) {
		return orderService.save(inDTO, userId);
	}

	@PostMapping(value = "/update/payStatus")
	public OutDTO updateOrderPayStatus(@RequestBody Map<String, String> map) {
		return orderService.updatePayStatus(map);
	}

	@GetMapping(value = "/detail/{orderCode}")
	@ApiOperation(value = "查询订单详情接口")
	@ApiImplicitParam(name = "orderCode", value = "订单编号", required = true, paramType = "path", dataType = "string")
	public OutDTO orderDetail(@PathVariable String orderCode) {
		if (StringUtils.isBlank(orderCode)) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "入参不合法");
		}
		OrderDetailDTO out;
		try {
			out = orderService.getDetailByCode(orderCode);
		} catch (DBNullException e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "订单不存在");
		} catch (RegimenProviderException e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, e.getMessage());
		} catch (Exception e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "服务异常！异常信息：" + e.getMessage());
		}
		return OutDTO.of(BOOLEAN_STRING_TRUE, "OK", "OK", out);
	}

	@PostMapping(value = "/submitReview")
	@ApiOperation(value = "订单评价提交")
	@ApiImplicitParam(name = "reviewData", value = "入参", required = true, paramType = "body", dataType = "OrderReviewSubmitInDTO")
	public OutDTO submitReview(@RequestBody OrderReviewSubmitInDTO reviewData) {
		if (reviewData == null || reviewData.isEmpty()) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "入参不合法");
		}
		try {
			return orderService.submitReview(reviewData);
		} catch (DBNullException e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "评价的订单不存在");
		} catch (ServiceException e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, e.getMessage());
		}
	}

	@GetMapping(value = "/review/{orderCode}")
	@ApiOperation(value = "根据订单编号查询订单评价")
	@ApiImplicitParam(name = "orderCode", value = "订单编号", required = true, paramType = "path", dataType = "string")
	public OutDTO queryOrderReview(@PathVariable String orderCode) {
		if (StringUtils.isBlank(orderCode)) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "入参不合法");
		}
		try {
			return orderService.queryReview(orderCode);
		} catch (Exception e) {
			return OutDTO.of(BOOLEAN_STRING_FALSE, "服务异常！异常信息：" + e.getMessage());
		}
	}

}
